using System.IO;
using UnityEngine.AddressableAssets;
using System;
using Newtonsoft.Json;
using UnityEngine;
using System.Collections.Generic;
using System.Linq;

#if UNITY_EDITOR
using UnityEditor.AddressableAssets.Settings.GroupSchemas;
using UnityEditor.AddressableAssets.Settings;
using UnityEditor.AddressableAssets;
using UnityEditor;
#endif

namespace Super
{
	public static class AssetUtil
	{
		#region  资源加载
		/// <summary>
		/// addressable 加载资源
		/// </summary>
		/// <typeparam name="T">加载资源的类型</typeparam>
		/// <returns></returns>
		public static T LoadAsset<T>(string path) where T : UnityEngine.Object
		{
			if (!AddrExist(path)) return null;
			T result = (T)Addressables.LoadAssetAsync<T>(path).WaitForCompletion();

			return result;
		}

		public static List<T> LoadAssets<T>(string label) where T : UnityEngine.Object
		{
			bool hasLable = false;
			foreach (var locator in Addressables.ResourceLocators)
			{
				if (locator.Keys.Contains(label))
				{
					hasLable = true;
					break;
				}
			}
			if (!hasLable) return new List<T>();

			List<T> result = (List<T>)Addressables.LoadAssetsAsync<T>(label, null).WaitForCompletion();
			return result;
		}

		/// <summary>
		/// addressable 的加载资源,并回调
		/// </summary>
		/// <typeparam name="T">加载资源的类型</typeparam>
		/// <param name="path">加载资源的路径</param>
		/// <param name="action">回调委托</param>
		public static void LoadAsset<T>(string path, Action<T> action)
		{
			Addressables.LoadAssetAsync<T>(path).Completed += (open) =>
			{
				action(open.Result);
			};
		}

		/// <summary>
		/// 编辑器模式下获取AA资源的AssetPath
		/// 默认情况下Addr应该和AssetPath保持一致。
		/// </summary>
		/// <param name="Addr"></param>
		/// <param name="groupName"></param>
		/// <returns></returns>
		public static string GetAssetPathByAddr(string Addr)
		{
			var operation = Addressables.LoadResourceLocationsAsync(Addr);
			var result = operation.WaitForCompletion();
			if (result == null || result.Count == 0)
				return "false";
			return result[0].InternalId;
		}

		/// <summary>
		/// 编辑器下判断是否存在AA资源
		/// </summary>
		/// <param name="Addr"></param>
		/// <returns></returns>
		public static bool AddrExist(string Addr)
		{
			if (string.IsNullOrEmpty(Addr)) return false;

			var operation = Addressables.LoadResourceLocationsAsync(Addr);
			var result = operation.WaitForCompletion();
			if (result == null || result.Count == 0)
				return false;
			return true;
		}

		/// <summary>
		/// 编辑器下判断是否存在AA资源
		///  OnValidate函数里面无法调用AddrExist函数
		/// </summary>
		/// <param name="Addr"></param>
		/// <returns></returns>
		public static bool EditorAddrExist(string Addr)
		{
			if (string.IsNullOrEmpty(Addr)) return false;

#if UNITY_EDITOR
			AddressableAssetSettings addressableSettings = AddressableAssetSettingsDefaultObject.Settings;
			foreach (var group in addressableSettings.groups)
			{
				foreach (var item in group.entries)
				{
					if (item.address == Addr)
					{
						return true;
					}
				}
			}
#endif
			return false;
		}

		/// <summary>
		/// 编辑器下判断是否存在资源
		/// </summary>
		/// <param name="assetPath"></param>
		/// <returns></returns>
		public static bool AssetExist(string assetPath)
		{
			if (string.IsNullOrEmpty(assetPath)) return false;
#if UNITY_EDITOR
			string absolutePath = GlobalUtil.GetAbsolutePath(assetPath);
			return File.Exists(absolutePath) || Directory.Exists(absolutePath);
#else
			return true;
#endif
		}

		/// <summary>
		/// addressable 创建或可寻址资源到Group中
		/// 默认assetPath为资源的寻址地址
		/// </summary>
		/// <param name="GroupName">资源的组名</param>
		/// <param name="assetPath">资源的寻址地址</param>
		public static void CreateOrMoveEntry(string GroupName, string assetPath, string label = "")
		{
#if UNITY_EDITOR
			assetPath = GlobalUtil.GetAssetsRelativePath(assetPath);
			string guiId = AssetDatabase.AssetPathToGUID(assetPath);

			AddressableAssetSettings addressableSettings = AddressableAssetSettingsDefaultObject.Settings;
			AddressableAssetEntry assetEntry = addressableSettings.FindAssetEntry(guiId);
			bool isExist = assetEntry != null && assetEntry.parentGroup.Name == GroupName;
			if (isExist) return;    //已存在就不用处理了

			AddressableAssetGroup customGroup = addressableSettings.FindGroup(GroupName);
			if (customGroup == null)
			{
				customGroup = addressableSettings.CreateGroup(GroupName, false, false, false, null, typeof(BundledAssetGroupSchema));
			}

			if (label != "")
			{
				if (!addressableSettings.GetLabels().Contains(label))
				{
					addressableSettings.AddLabel(label);
				}

				if (!assetEntry.labels.Contains(label))
				{
					assetEntry.labels.Add(label);
				}
			}

			addressableSettings.CreateOrMoveEntry(guiId, customGroup);
			Debug.Log($"{assetPath}移动到AddressGroup：{GroupName}AddressGroup中");
#endif
		}

		#endregion

		#region 游戏长久保存数据

		/// <summary>
		/// 保存游戏数据
		/// </summary>
		/// <typeparam name="T">需要保存数据的类型 某个类</typeparam>
		/// <param name="path">保存的资源路径例如"RanKData/TestScript.sav"</param>
		/// <param name="data">保存的数据</param>
		public static void SavePersistentData<T>(string path, T data)
		{
			string directory = Path.GetDirectoryName(path);
			string fileName = Path.GetFileName(path);
			string saveText = JsonConvert.SerializeObject(data);

			SavePersistentData(directory, fileName, saveText);
		}

		/// <summary>
		/// 以RSA方式加密，保存数据
		/// </summary>
		/// <typeparam name="T">需要保存数据的类型 某个类</typeparam>
		/// <param name="path">保存的资源路径例如"RanKData/TestScript.sav"</param>
		/// <param name="data">保存的数据</param>
		public static void SavePersistentEncryptData<T>(string path, T data)
		{
			string directory = Path.GetDirectoryName(path);
			string fileName = Path.GetFileName(path);
			string saveText = JsonConvert.SerializeObject(data);
			string encryptText = EncryptUtil.Encrypt(saveText, ValueSettingSO.Ins.PublicKey_RSAXml);

			SavePersistentData(directory, fileName, encryptText);
		}

		private static void SavePersistentData(string directory, string fileName, string text)
		{
			directory = GlobalUtil.GetPersistentDataPath(directory);
			if (!Directory.Exists(directory))
			{
				Directory.CreateDirectory(directory);
			}

			string filePath = GlobalUtil.Combine(directory, fileName);
			StreamWriter sw = new StreamWriter(filePath);
			sw.Write(text);
			sw.Flush();
			sw.Close();
		}

		/// <summary>
		/// 读取游戏数据
		/// </summary>
		/// <typeparam name="T">资源类型</typeparam>
		/// <param name="path">读取的资源路径例如"RanKData/TestScript.cs"</param>
		/// <returns>返回保存的对象</returns>
		public static T LoadPersistentData<T>(string path)
		{
			string directory = Path.GetDirectoryName(path);
			string fileName = Path.GetFileName(path);
			string saveText = LoadPersistentData(directory, fileName);

			if (String.IsNullOrEmpty(saveText))
				return default(T);

			T data = JsonConvert.DeserializeObject<T>(saveText);
			return data;
		}

		/// <summary>
		/// 读取游戏数据,并且以RSA算法进行解密
		/// </summary>
		/// <typeparam name="T">资源类型</typeparam>
		/// <param name="path">读取的资源路径例如"RanKData/TestScript.cs"</param>
		/// <returns>返回保存的对象</returns>
		public static T LoadPersistentEncryptData<T>(string path)
		{
			string directory = Path.GetDirectoryName(path);
			string fileName = Path.GetFileName(path);
			string encryptText = LoadPersistentData(directory, fileName);
			if (String.IsNullOrEmpty(encryptText))
				return default(T);


			string decryptedText = EncryptUtil.Decrypt(encryptText, ValueSettingSO.Ins.PrivateKey_RSAXml);
			T data = JsonConvert.DeserializeObject<T>(decryptedText);

			return data;
		}

		private static string LoadPersistentData(string directory, string fileName)
		{
			directory = GlobalUtil.GetPersistentDataPath(directory);
			string saveText = "";
			string filePath = GlobalUtil.Combine(directory, fileName);
			if (File.Exists(filePath))
			{
				StreamReader sr = new StreamReader(filePath);
				saveText = sr.ReadToEnd();
				sr.Close();
			}

			return saveText;
		}

		#endregion

		#region 创建文件、目录

		/// <summary>
		/// 保存文本，脚本内容
		/// 资源路径是Assets开头的相对路径
		/// </summary>
		/// <param name="path">文本资源路径 例如Assets/FrameWork/ExcelTool/CustomExcelDataClass/Sheet2_SO.cs</param>
		/// <param name="content">文本内容</param>
		public static void CreateFileUnRefresh(string path, string content)
		{
			path = GlobalUtil.GetAbsolutePath(path);
			string directory = Path.GetDirectoryName(path);
			if (!Directory.Exists(directory))
			{
				Directory.CreateDirectory(directory);
				Debug.Log($"创建{directory}目录");
			}
			StreamWriter sw = new StreamWriter(path);
			sw.Write(content);
			sw.Close();
		}

		/// <summary>
		/// 保存文本，脚本内容
		/// 资源路径是Assets开头的相对路径
		/// </summary>
		/// <param name="path">文本资源路径 例如Assets/FrameWork/ExcelTool/CustomExcelDataClass/Sheet2_SO.cs</param>
		/// <param name="content">文本内容</param>
		public static void CreateFile(string path, string content)
		{
			CreateFileUnRefresh(path, content);
#if UNITY_EDITOR
			AssetDatabase.Refresh();
#endif
		}

		public static bool TryCreateDirectory(string path)
		{
			path = GlobalUtil.GetAbsolutePath(path);
			string directory = Path.GetDirectoryName(path);
			if (!Directory.Exists(directory))
			{
				Directory.CreateDirectory(directory);
				Debug.Log($"创建{directory}目录");
				return true;
			}
			return false;
		}

		/// <summary>
		/// 不存在目录或文件时创建，创建文件后返回true
		/// </summary>
		/// <param name="path"></param>
		/// <returns></returns>
		public static bool TryCreateDirectoryAndFile(string path, string content = "")
		{
			path = GlobalUtil.GetAbsolutePath(path);
			string directory = Path.GetDirectoryName(path);
			bool isCreated = false;
			if (!Directory.Exists(directory))
			{
				Directory.CreateDirectory(directory);
				isCreated = true;
				Debug.Log($"创建{directory}目录");
			}
			if (!File.Exists(path))
			{
				CreateFile(path, content);
				isCreated = true;
				Debug.Log($"创建{path}文件");
			}

			return isCreated;
		}


		/// <summary>
		/// 保存数据到文件
		/// </summary>
		/// <param name="assetPath">项目路径下的文件路径</param>
		/// <param name="data"></param>
		/// <typeparam name="T"></typeparam>
		public static void SaveToFile<T>(string assetPath, T data)
		{
			string saveText = JsonConvert.SerializeObject(data);
			CreateFile(assetPath, saveText);
		}

		/// <summary>
		/// 从文件中读取数据
		/// </summary>
		/// <param name="assetPath"></param>
		/// <typeparam name="T"></typeparam>
		/// <returns></returns>
		public static T ReadFromFile<T>(string assetPath)
		{
			if (!AssetExist(assetPath)) return default(T);
			string path = GlobalUtil.GetAbsolutePath(assetPath);
			string saveText = "";
			if (File.Exists(path))
			{
				StreamReader sr = new StreamReader(path);
				saveText = sr.ReadToEnd();
				sr.Close();
			}

			if (string.IsNullOrEmpty(saveText)) return default(T);


			T data = JsonConvert.DeserializeObject<T>(saveText);
			return data;
		}

		#endregion

		#region 复制目录

		public static void CopyDirectory(string sourceDir, string targetDir)
		{
			sourceDir = GlobalUtil.GetAbsolutePath(sourceDir);
			targetDir = GlobalUtil.GetAbsolutePath(targetDir);

			if (!Directory.Exists(targetDir))
			{
				Directory.CreateDirectory(targetDir);
			}
			string[] files = Directory.GetFiles(sourceDir);
			foreach (string file in files)
			{
				string pFilePath = Path.Combine(targetDir, Path.GetFileName(file));
				if (File.Exists(pFilePath))
					continue;
				File.Copy(file, pFilePath, true);
			}

			string[] dirs = Directory.GetDirectories(sourceDir);
			foreach (string dir in dirs)
			{
				CopyDirectory(dir, Path.Combine(targetDir, Path.GetFileName(dir)));
			}
		}

		#endregion
	}

}
